package cn.jdy.payment.service;

import java.io.UnsupportedEncodingException;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import org.hibernate.SQLQuery;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.jdy.common.constant.BankConstant;
import cn.jdy.common.constant.GlobalConstant;
import cn.jdy.framework.db.hibernate.BaseDao;
import cn.jdy.framework.log.BaseLog;
import cn.jdy.framework.util.DateUtil;
import cn.jdy.framework.util.SpringContextUtils;
import cn.jdy.framework.util.StringUtil;
import cn.jdy.payment.entity.MerchantInfo;
import cn.jdy.payment.entity.OrderParameter;
import cn.jdy.payment.entity.Orders;
import cn.jdy.plugins.entity.Business;
import cn.jdy.plugins.entity.Member;
import cn.jdy.plugins.service.BusinessService;
import cn.jdy.plugins.service.MemberService;
import cn.jdy.task.entity.SchedulingJob;
import cn.jdy.task.service.SchedulerService;
import cn.jdy.task.service.classify.OrderAutoCancel;

@Service
@DependsOn("springContextUtils")
public class OrderService extends BaseDao<Orders> {

	@Autowired
	private MerchantService merchantService;
	@Autowired
	private BusinessService businessService;
	@Autowired
	private MemberService memberService;
	@Autowired
	private SchedulerService schedulerService;

	public Orders queryOrderById(String orderNo) {
		return super.find(orderNo);
	}

	/**
	 * 判断用户是否购买过某商品
	 * @param userId
	 * @param goodsNo
	 * @return
	 */
	public boolean queryHasOrder(String userId, String goodsNo) {
		return queryHasOrder(userId, goodsNo, new String[]{BankConstant.ORDER_SUC});
	}

	/**
	 * 判断用户是否拥有某商品的订单
	 * @param userId
	 * @param goodsNo
	 * @return
	 */
	public boolean queryHasOrder(String userId, String goodsNo, String[] status) {
		List list = super.find("userId", userId, "goodsNo", goodsNo, "status", status[0]);
		return list!=null && list.size()>0;
	}

	/**
	 * 根据条件查询订单
	 *
	 * @param order
	 * @return
	 */
	public List<Orders> queryOrders(Orders order, String... date) {
		return super.find(createCriteria(order, date), order.getiDisplayStart(), order.getiDisplayLength());
	}

	/**
	 * 查询指定条件的记录数
	 *
	 * @param order
	 * @return
	 */
	public Long count(Orders order, String... date) {
		return super.count(createCriteria(order, date));
	}

	/**
	 * 拼装条件
	 *
	 * @param entity
	 * @param page
	 * @return
	 */
	private DetachedCriteria createCriteria(Orders entity, String... date) {
		DetachedCriteria dc = DetachedCriteria.forClass(super.entityClass);
		dc.addOrder(Order.desc("orderDate"));
		if(date.length>0 && date[0]!=null && date[1]!=null && date[0].length()>0 && date[1].length()>0) {
			dc.add(Restrictions.between("orderDate", date[0], date[1]));
		}
		if(StringUtil.isNotEmpty(entity.getUserId())) {
			dc.add(Restrictions.eq("userId", entity.getUserId()));
		}
		if(StringUtil.isNotEmpty(entity.getStatus())) {
			dc.add(Restrictions.eq("status", entity.getStatus()));
		}
		if(StringUtil.isNotEmpty(entity.getId())) {
			dc.add(Restrictions.eq("id", entity.getId()));
		}
		if(StringUtil.isNotEmpty(entity.getGoodsName())) {
			dc.add(Restrictions.like("goodsName", entity.getGoodsName(),MatchMode.ANYWHERE));
		}
		if(StringUtil.isNotEmpty(entity.getGoodsNo())) {
			dc.add(Restrictions.eq("goodsNo", entity.getGoodsNo()));
		}
		if(StringUtil.isNotEmpty(entity.getOrderType())) {
			dc.add(Restrictions.eq("orderType", entity.getOrderType()));
		}
		return dc;
	}

	/**
	 * 生成订单
	 */
	public Orders createOrder(OrderParameter param) throws UnsupportedEncodingException {

		Orders order = new Orders();
		//订单基本信息区
		order.setId(SerialNumberUtil.buildOrderNo());
		order.setUserId(param.getUserId());
		order.setUserName(param.getUserName());
		order.setsMoney(param.getsMoney());
		order.setAmount(String.format("%.2f", param.getMoney()));
		order.setOrderType(param.getOrderType());
		order.setCurType(BankConstant.CURTYPE_RMB);
		order.setStatus(BankConstant.ORDER_UNPAY);
		order.setChargeStatus(BankConstant.CHARGEAMT_INIT);
		order.setExchange(BankConstant.EXCHANGE);
		order.setOrderDate(DateUtil.getCurrentDate(DateUtil._DEFAULT2));
		order.setOperIp(param.getOperIp());
		order.setGoodsNo(param.getGoodNo());
		order.setGoodsName((param.getGoodNo()==null || "0".equals(param.getGoodNo())) ? "sjwwh" : businessService.queryById(param.getGoodNo()).getSummary());
		order.setGoodsNum(param.getGoodSum());

		if(param.getMoney() > 0) {
			order.setBankNo(param.getBankNo());
			order = createOrderBankData(order);
		}
		super.save(order);
		return order;
	}

	/**
	 * 拼接银行数据
	 */
	public Orders createOrderBankData(Orders order) throws UnsupportedEncodingException {
		MerchantInfo merchant = merchantService.queryMerchantById(order.getBankNo());
		if(merchant == null) return null;
		order.setBankName(merchant.getPayChannel().getBankName());
		order.setBankAddr(merchant.getPayChannel().getGateWay());
		BankBusiServer bankBusi = SpringContextUtils.getBean("bankBusi".concat(order.getBankNo()));
		order = bankBusi.placeOrder(order, merchant);
		return order;
	}

	/**
	 * 银行回调
	 */
	public Orders notify(String bankType, Map<String, String> param) throws SQLException {
		Orders order = null;
		String bankNo = BankConstant.bankNoMap.get(bankType);
		if(bankNo != null && bankNo.length() > 0) {
			BankBusiServer bankBusi = SpringContextUtils.getBean("bankBusi".concat(bankNo));
			if(bankBusi != null) order = bankBusi.notify(param);
			if(order != null) bankNotifyHandle(order);
		}
		return order;
	}

	/**
	 * 银行回调辅助方法
	 *
	 * @param order
	 * @return
	 */
	public String bankNotifyHandle(Orders order) throws SQLException {
		if(order == null || BankConstant.ORDER_UNPAY.equals(order.getStatus())) return null;
		String result = null;
		if(BankConstant.ORDER_SUC.equals(order.getStatus())) {
			if(!BankConstant.CHARGEAMT_SUC.equals(order.getChargeStatus())) {
				Member member = memberService.find(order.getUserId());
				//0代表充值
				if(BankConstant.ORDER_TYPE_TOPUP.equals(order.getOrderType())) {
					member.setMoney(member.getMoney() + order.getsMoney());
					order.setChargeStatus(BankConstant.CHARGEAMT_SUC);
				} else {
					Business business = businessService.find(order.getGoodsNo());
					//修改对应商机信息的下载次数
					business.setBuyTimes((business.getBuyTimes() == null ? 0 : business.getBuyTimes()) + 1);
					//判断商机信息的库存和下载次数是否更新成功
					businessService.update(business);
					memberService.updateMoney(member.getId(), GlobalConstant.SMONEY_BUSINESS_BUY);
				}
				memberService.update(member);
			}

			//更新订单
			super.update(order);

			result = BankConstant.BACK_BUSI_HANDLE_SUC;
		} else {
			result = BankConstant.BACK_BUSI_HANDLE_FAIL;
		}
		return result;
	}

	/**
	 * 取消订单
	 * @param orderNo
	 * @return
	 */
	@Transactional
	public String cancel(String orderNo) throws SQLException, SchedulerException {
		Orders order = this.queryOrderById(orderNo);
		if(order==null) return null;
			if(BankConstant.ORDER_TYPE_PAY.equals(order.getOrderType()) && order.getsMoney()>0) {
				Member member = memberService.find(order.getUserId());
				member.setMoney(member.getMoney() + order.getsMoney());
				memberService.update(member);
			}
			deleteScheduler(orderNo);
			order.setStatus(BankConstant.ORDER_CANCEL);
			super.update(order);
		return order.getStatus();
	}

	public void addScheduler(String orderNo) {
		//添加定时任务
		SchedulingJob entity = new SchedulingJob();
		entity.setJobGroup(OrderAutoCancel.class.getName());
		entity.setJobName("订单关闭".concat(orderNo));
		entity.setStatus(SchedulingJob.JS_ENABLED);
		entity.setOwer(SchedulingJob.OWER_SHOP);
		entity.setStrParam(orderNo);
		entity.setCronExpression(DateUtil.getAfterDate("ss mm HH dd MM ? yyyy", 3));
		try {
			schedulerService.saveOrUpd(entity);
		} catch(SchedulerException e) {
			BaseLog.e(this.getClass(), "addScheduler", e);
		} catch(ClassNotFoundException e) {
			BaseLog.e(this.getClass(), "addScheduler", e);
		}
	}
	
	public void deleteScheduler(String orderNo) throws SchedulerException {
		List<SchedulingJob> list = schedulerService.find("strParam", orderNo, "jobGroup", OrderAutoCancel.class.getName());
		if(list!=null && list.size()>0) schedulerService.delete(list.get(0).getId());
	}
	
	public String getLastOrderNo() {
    SQLQuery query = super.em().createSQLQuery("select max(id) from orders");
    return String.valueOf(query.uniqueResult());
  }
	
}
